package xyz.fivefaith.faithtool.redis;

import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import xyz.fivefaith.faithtool.redis.constant.RedisConstant;

import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * redis工具类
 *
 * @author zhaoanchi
 * @version 1.0
 * @since 1.0
 */
public final class RedisUtil {
    private static final RedissonClient CLIENT;

    /* ---------- 静态块：加载 redis.properties ---------- */
    static {
        Properties props = new Properties();
        try (InputStream in =
                RedisUtil.class
                        .getClassLoader()
                        .getResourceAsStream(RedisConstant.REDIS_CONFIG_PATH)) {
            if (in == null) {
                throw new RuntimeException("redis.properties not found in classpath");
            }
            props.load(in);
        } catch (IOException e) {
            throw new RuntimeException("load redis.properties error", e);
        }

        String host = props.getProperty("redis.host", "127.0.0.1");
        int port = Integer.parseInt(props.getProperty("redis.port", "6379"));
        String password = props.getProperty("redis.password");
        int db = Integer.parseInt(props.getProperty("redis.database", "0"));

        Config config = new Config();
        config.useSingleServer().setAddress("redis://" + host + ":" + port).setDatabase(db);
        if (password != null && !password.isBlank()) {
            config.useSingleServer().setPassword(password);
        }

        CLIENT = Redisson.create(config);
    }

    /* ---------- 工具方法 ---------- */

    /** 检查值是否存在 */
    public boolean isExist(String key) {
        return CLIENT.getBucket(key).isExists();
    }

    /* ================= 普通 KV ================= */

    /** 设置值 */
    public <T> void set(String key, T value) {
        CLIENT.getBucket(key).set(value);
    }

    /** 设置值 + 过期时间 */
    public <T> void setEx(String key, T value, Duration duration) {
        CLIENT.getBucket(key).set(value, duration);
    }

    /** 取值 */
    public <T> T get(String key) {
        RBucket<T> bucket = CLIENT.getBucket(key);
        return bucket.get();
    }

    /** 删除 */
    public boolean del(String key) {
        return CLIENT.getBucket(key).delete();
    }

    /* ================= 计数器 ================= */

    /** 原子递增（不存在则先置 0 再 +1） */
    public long incr(String key) {
        return CLIENT.getAtomicLong(key).incrementAndGet();
    }

    /** 原子递增指定步长 */
    public long incrBy(String key, long delta) {
        return CLIENT.getAtomicLong(key).addAndGet(delta);
    }

    /* ================= 分布式锁 ================= */

    /** 获取分布式锁 */
    public RLock lock(String key) {
        return CLIENT.getLock(key);
    }

    /** 获取针对该 key 的公平锁 */
    public RLock fairLock(String key) {
        return CLIENT.getFairLock(key);
    }

    /** 尝试加锁（最多等待 waitTime，锁自动释放 leaseTime） */
    public boolean tryLock(String key, long waitTime, long leaseTime, TimeUnit unit)
            throws InterruptedException {
        return lock(key).tryLock(waitTime, leaseTime, unit);
    }

    /** 释放锁 */
    public void unlock(String key) {
        RLock lock = lock(key);
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /** 释放锁 */
    public void unFairLock(String key) {
        RLock lock = fairLock(key);
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /* ===== Object bucket (任意类型) ===== */
    public static <T> RBucket<T> getBucket(String key) {
        return CLIENT.getBucket(key);
    }

    /* ---------- 其余工具方法保持不变 ---------- */
    public static void shutdown() {
        CLIENT.shutdown();
    }
}
